package com.coman404.ws;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

/**
 * @author NotFound404 at 2024/6/12
 * code code always code
 */
public class WsServer {


    private static Channel channel;

    private static EventLoopGroup boss = new NioEventLoopGroup(1);
    private static EventLoopGroup work = new NioEventLoopGroup();

    public static void startServer() {
        ServerBootstrap server = new ServerBootstrap();
        server.group(boss, work);
        server.channel(NioServerSocketChannel.class)
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .handler(new LoggingHandler(LogLevel.DEBUG))
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        ChannelPipeline pipeline = channel.pipeline();
                        pipeline.addLast(new HttpServerCodec());
                        pipeline.addLast(new HttpObjectAggregator(65535));
                        pipeline.addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS));
                        pipeline.addLast(new HeartbeatHandler());
                        pipeline.addLast(new WebSocketPathValidatorHandler("/netty/websocket/*"));
//                        pipeline.addLast(new WebSocketServerProtocolHandler("/netty/websocket", null,true));
//                        pipeline.addLast(chatMessageHandler);
                    }
                });
        ChannelFuture channelFuture = server.bind(8088);
        try {
            System.out.println("websocket server started");
            channel = channelFuture.sync().channel();
        } catch (InterruptedException e) {
            System.out.println("websocket server start failed");
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        startServer();
    }

    public static void destroy(){
        System.out.println("websocket server closed");
        if (channel!=null){
            channel.close();
        }
        boss.shutdownGracefully();
        work.shutdownGracefully();
    }

    static class WebSocketPathValidatorHandler extends ChannelInboundHandlerAdapter {

        private final String wildcardPath; // 例如 "/ws/*"

        public WebSocketPathValidatorHandler(String wildcardPath) {
            this.wildcardPath = wildcardPath;
        }

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof FullHttpRequest) {
                FullHttpRequest request = (FullHttpRequest) msg;

                // 检查请求的 URI 是否符合通配符路径
                String uri = request.uri();
                boolean isMatch = uri.startsWith(wildcardPath.substring(0, wildcardPath.indexOf('*')-1));
                String token = request.headers().get("Sec-Websocket-Protocol");
                if (isMatch) {
                    // 路径匹配，继续 WebSocket 握手
                    // 添加 WebSocketServerProtocolHandler 到 pipeline
                    ctx.pipeline().addLast(new WebSocketServerProtocolHandler(uri, token, true));
                    ctx.pipeline().addLast(new WsMessageHandler());
                } else {
                    ctx.channel().close();
                }
                super.channelRead(ctx,msg);
            } else {
                super.channelRead(ctx, msg);
            }
        }
    }

}
